package com.rpc.serializer;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rpc.model.RpcRequest;
import com.rpc.model.RpcResponse;

import java.io.IOException;

public class JsonSerializer implements Serializer {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public <T> byte[] serialize(T object) throws IOException {
        return objectMapper.writeValueAsBytes(object);
    }

    /**
     *
     * @param bytes
     * @param type
     * @param <T>
     * @return
     * @throws IOException
     */
    @Override
    public <T> T deserialize(byte[] bytes, Class<T> type) throws IOException {
        T obj = objectMapper.readValue(bytes, type);
        if( obj instanceof RpcRequest) {
            return handleRequest((RpcRequest) obj, type);
        }
        if(obj instanceof RpcResponse) {
            return handleResponse((RpcResponse)obj, type);
        }
        return obj;
    }

    /**
     * 由于Object原始对象会被擦除，导致反序列化时会被当做LinkedHashMap无法转换成原始类型，一次做特殊处理
     * @param response
     * @param type
     * @param <T>
     * @return
     */
    private <T> T handleResponse(RpcResponse response, Class<T> type) throws IOException {
        //处理响应数据
        byte[] dataBytes = objectMapper.writeValueAsBytes(response.getData());
        response.setData(objectMapper.readValue(dataBytes, response.getDataType()));
        return type.cast(response);
    }

    /**
     * 由于Object原始对象类型会被擦除，导致反序列化时会被作为LinkedHashMap无法转换成原始对象，因此需要做特殊处理
     * @param rpcRequest
     * @param type
     * @param <T>
     * @return
     */
    private <T> T handleRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] args = rpcRequest.getArgs();

        //循环处理每个参数类型
        for(int i = 0; i < parameterTypes.length; i ++){
            Class<?> clazz = parameterTypes[i];
            //如果类型不同，则重置处理一下类型
            if(!clazz.isAssignableFrom(clazz)) {
                byte[] argBytes = objectMapper.writeValueAsBytes(args[i]);
                args[i] = objectMapper.readValue(argBytes, clazz);
            }
        }
        return type.cast(rpcRequest);
    }
}
